fbe449
@@ -53,31 +53,6 @@
public class JpaActiveRecordMetadata extends
     private static final String PROVIDES_TYPE = MetadataIdentificationUtils
             .create(PROVIDES_TYPE_STRING);
 
-    public static String createIdentifier(final JavaType javaType,
-            final LogicalPath path) {
-        return PhysicalTypeIdentifierNamingUtils.createIdentifier(
-                PROVIDES_TYPE_STRING, javaType, path);
-    }
-
-    public static JavaType getJavaType(final String metadataIdentificationString) {
-        return PhysicalTypeIdentifierNamingUtils.getJavaType(
-                PROVIDES_TYPE_STRING, metadataIdentificationString);
-    }
-
-    public static String getMetadataIdentifierType() {
-        return PROVIDES_TYPE;
-    }
-
-    public static LogicalPath getPath(final String metadataIdentificationString) {
-        return PhysicalTypeIdentifierNamingUtils.getPath(PROVIDES_TYPE_STRING,
-                metadataIdentificationString);
-    }
-
-    public static boolean isValid(final String metadataIdentificationString) {
-        return PhysicalTypeIdentifierNamingUtils.isValid(PROVIDES_TYPE_STRING,
-                metadataIdentificationString);
-    }
-
     private JpaCrudAnnotationValues crudAnnotationValues;
     private MethodMetadata entityManagerMethod;
     private String entityName;
@@ -109,18 +84,18 @@
public class JpaActiveRecordMetadata extends
             final String entityName, final boolean isGaeEnabled) {
         super(metadataIdentificationString, aspectName,
                 governorPhysicalTypeMetadata);
-        Validate.isTrue(isValid(metadataIdentificationString),
-                "Metadata identification string '"
-                        + metadataIdentificationString
-                        + "' does not appear to be a valid");
+        Validate.isTrue(
+                isValid(metadataIdentificationString),
+                "Metadata identification string '%s' does not appear to be a valid",
+                metadataIdentificationString);
         Validate.notNull(crudAnnotationValues,
                 "CRUD-related annotation values required");
-        Validate.notNull(identifierField, "Identifier required for '"
-                + metadataIdentificationString + "'");
-        Validate.notBlank(entityName, "Entity name required for '"
-                + metadataIdentificationString + "'");
-        Validate.notBlank(plural, "Plural required for '"
-                + metadataIdentificationString + "'");
+        Validate.notNull(identifierField, "Identifier required for '%s'",
+                metadataIdentificationString);
+        Validate.notBlank(entityName, "Entity name required for '%s'",
+                metadataIdentificationString);
+        Validate.notBlank(plural, "Plural required for '%s'",
+                metadataIdentificationString);
 
         if (!isValid()) {
             return;
@@ -158,6 +133,162 @@
public class JpaActiveRecordMetadata extends
         itdTypeDetails = builder.build();
     }
 
+    public static String createIdentifier(final JavaType javaType,
+            final LogicalPath path) {
+        return PhysicalTypeIdentifierNamingUtils.createIdentifier(
+                PROVIDES_TYPE_STRING, javaType, path);
+    }
+
+    public static JavaType getJavaType(final String metadataIdentificationString) {
+        return PhysicalTypeIdentifierNamingUtils.getJavaType(
+                PROVIDES_TYPE_STRING, metadataIdentificationString);
+    }
+
+    public static String getMetadataIdentifierType() {
+        return PROVIDES_TYPE;
+    }
+
+    public static LogicalPath getPath(final String metadataIdentificationString) {
+        return PhysicalTypeIdentifierNamingUtils.getPath(PROVIDES_TYPE_STRING,
+                metadataIdentificationString);
+    }
+
+    public static boolean isValid(final String metadataIdentificationString) {
+        return PhysicalTypeIdentifierNamingUtils.isValid(PROVIDES_TYPE_STRING,
+                metadataIdentificationString);
+    }
+
+    /**
+     * @return the dynamic, custom finders (never returns null, but may return
+     *         an empty list)
+     */
+    public List<String> getDynamicFinders() {
+        if (crudAnnotationValues.getFinders() == null) {
+            return Collections.emptyList();
+        }
+        return Arrays.asList(crudAnnotationValues.getFinders());
+    }
+
+    /**
+     * Locates the entity manager field that should be used.
+     * <p>
+     * If a parent is defined, it must provide the field.
+     * <p>
+     * We generally expect the field to be named "entityManager" and be of type
+     * javax.persistence.EntityManager. We also require it to be public or
+     * protected, and annotated with @PersistenceContext. If there is an
+     * existing field which doesn't meet these latter requirements, we add an
+     * underscore prefix to the "entityManager" name and try again, until such
+     * time as we come up with a unique name that either meets the requirements
+     * or the name is not used and we will create it.
+     * 
+     * @return the entity manager field (never returns null)
+     */
+    public FieldMetadata getEntityManagerField() {
+        if (parent != null) {
+            // The parent is required to guarantee this is available
+            return parent.getEntityManagerField();
+        }
+
+        // Need to locate it ourself
+        int index = -1;
+        while (true) {
+            // Compute the required field name
+            index++;
+            final JavaSymbolName fieldSymbolName = new JavaSymbolName(
+                    StringUtils.repeat("_", index) + "entityManager");
+            final FieldMetadata candidate = governorTypeDetails
+                    .getField(fieldSymbolName);
+            if (candidate != null) {
+                // Verify if candidate is suitable
+
+                if (!Modifier.isPublic(candidate.getModifier())
+                        && !Modifier.isProtected(candidate.getModifier())
+                        && Modifier.TRANSIENT != candidate.getModifier()) {
+                    // Candidate is not public and not protected and not simply
+                    // a transient field (in which case subclasses
+                    // will see the inherited field), so any subsequent
+                    // subclasses won't be able to see it. Give up!
+                    continue;
+                }
+
+                if (!candidate.getFieldType().equals(ENTITY_MANAGER)) {
+                    // Candidate isn't an EntityManager, so give up
+                    continue;
+                }
+
+                if (MemberFindingUtils.getAnnotationOfType(
+                        candidate.getAnnotations(), PERSISTENCE_CONTEXT) == null) {
+                    // Candidate doesn't have a PersistenceContext annotation,
+                    // so give up
+                    continue;
+                }
+
+                // If we got this far, we found a valid candidate
+                return candidate;
+            }
+
+            // Candidate not found, so let's create one
+            final List<AnnotationMetadataBuilder> annotations = new ArrayList<AnnotationMetadataBuilder>();
+            final AnnotationMetadataBuilder annotationBuilder = new AnnotationMetadataBuilder(
+                    PERSISTENCE_CONTEXT);
+            if (StringUtils.isNotBlank(crudAnnotationValues
+                    .getPersistenceUnit())) {
+                annotationBuilder.addStringAttribute("unitName",
+                        crudAnnotationValues.getPersistenceUnit());
+            }
+            annotations.add(annotationBuilder);
+
+            return new FieldMetadataBuilder(getId(), Modifier.TRANSIENT,
+                    annotations, fieldSymbolName, ENTITY_MANAGER).build();
+        }
+    }
+
+    /**
+     * @return the static utility entityManager() method used by other methods
+     *         to obtain entity manager and available as a utility for user code
+     *         (never returns nulls)
+     */
+    public MethodMetadata getEntityManagerMethod() {
+        return entityManagerMethod;
+    }
+
+    /**
+     * Returns the JPA name of this entity.
+     * 
+     * @return a non-<code>null</code> name (might be empty)
+     */
+    public String getEntityName() {
+        return entityName;
+    }
+
+    /**
+     * @return the find (by ID) method (may return null)
+     */
+    public MethodMetadata getFindMethod() {
+        return findMethod;
+    }
+
+    /**
+     * @return the pluralised name (never returns null or an empty string)
+     */
+    public String getPlural() {
+        return plural;
+    }
+
+    @Override
+    public String toString() {
+        final ToStringBuilder builder = new ToStringBuilder(this);
+        builder.append("identifier", getId());
+        builder.append("valid", valid);
+        builder.append("aspectName", aspectName);
+        builder.append("destinationType", destination);
+        builder.append("finders", crudAnnotationValues.getFinders());
+        builder.append("governor", governorPhysicalTypeMetadata.getId());
+        builder.append("itdTypeDetails", itdTypeDetails);
+        return builder.toString();
+    }
+
     private void addTransactionalAnnotation(
             final List<AnnotationMetadataBuilder> annotations) {
         addTransactionalAnnotation(annotations, false);
@@ -218,9 +349,10 @@
public class JpaActiveRecordMetadata extends
                 parameterTypes);
         if (userMethod != null) {
             Validate.isTrue(userMethod.getReturnType()
-                    .equals(COUNT_RETURN_TYPE), "Method '" + methodName
-                    + "' on '" + destination + "' must return '"
-                    + COUNT_RETURN_TYPE.getNameIncludingTypeParameters() + "'");
+                    .equals(COUNT_RETURN_TYPE),
+                    "Method '%s' on %s must return '%s'", methodName,
+                    destination,
+                    COUNT_RETURN_TYPE.getNameIncludingTypeParameters() + "'");
             return userMethod;
         }
 
@@ -231,9 +363,15 @@
public class JpaActiveRecordMetadata extends
         }
 
         final InvocableMemberBodyBuilder bodyBuilder = new InvocableMemberBodyBuilder();
-        bodyBuilder.appendFormalLine("return " + ENTITY_MANAGER_METHOD_NAME
-                + "().createQuery(\"SELECT COUNT(o) FROM " + entityName
-                + " o\", Long.class).getSingleResult();");
+        if (isGaeEnabled) {
+            bodyBuilder.appendFormalLine("return "
+                    + getFindAllMethod().getMethodName() + "().size();");
+        }
+        else {
+            bodyBuilder.appendFormalLine("return " + ENTITY_MANAGER_METHOD_NAME
+                    + "().createQuery(\"SELECT COUNT(o) FROM " + entityName
+                    + " o\", Long.class).getSingleResult();");
+        }
 
         final MethodMetadataBuilder methodBuilder = new MethodMetadataBuilder(
                 getId(), Modifier.PUBLIC | Modifier.STATIC, methodName,
@@ -330,110 +468,6 @@
public class JpaActiveRecordMetadata extends
         return methodBuilder;
     }
 
-    /**
-     * @return the dynamic, custom finders (never returns null, but may return
-     *         an empty list)
-     */
-    public List<String> getDynamicFinders() {
-        if (crudAnnotationValues.getFinders() == null) {
-            return Collections.emptyList();
-        }
-        return Arrays.asList(crudAnnotationValues.getFinders());
-    }
-
-    /**
-     * Locates the entity manager field that should be used.
-     * <p>
-     * If a parent is defined, it must provide the field.
-     * <p>
-     * We generally expect the field to be named "entityManager" and be of type
-     * javax.persistence.EntityManager. We also require it to be public or
-     * protected, and annotated with @PersistenceContext. If there is an
-     * existing field which doesn't meet these latter requirements, we add an
-     * underscore prefix to the "entityManager" name and try again, until such
-     * time as we come up with a unique name that either meets the requirements
-     * or the name is not used and we will create it.
-     * 
-     * @return the entity manager field (never returns null)
-     */
-    public FieldMetadata getEntityManagerField() {
-        if (parent != null) {
-            // The parent is required to guarantee this is available
-            return parent.getEntityManagerField();
-        }
-
-        // Need to locate it ourself
-        int index = -1;
-        while (true) {
-            // Compute the required field name
-            index++;
-            final JavaSymbolName fieldSymbolName = new JavaSymbolName(
-                    StringUtils.repeat("_", index) + "entityManager");
-            final FieldMetadata candidate = governorTypeDetails
-                    .getField(fieldSymbolName);
-            if (candidate != null) {
-                // Verify if candidate is suitable
-
-                if (!Modifier.isPublic(candidate.getModifier())
-                        && !Modifier.isProtected(candidate.getModifier())
-                        && Modifier.TRANSIENT != candidate.getModifier()) {
-                    // Candidate is not public and not protected and not simply
-                    // a transient field (in which case subclasses
-                    // will see the inherited field), so any subsequent
-                    // subclasses won't be able to see it. Give up!
-                    continue;
-                }
-
-                if (!candidate.getFieldType().equals(ENTITY_MANAGER)) {
-                    // Candidate isn't an EntityManager, so give up
-                    continue;
-                }
-
-                if (MemberFindingUtils.getAnnotationOfType(
-                        candidate.getAnnotations(), PERSISTENCE_CONTEXT) == null) {
-                    // Candidate doesn't have a PersistenceContext annotation,
-                    // so give up
-                    continue;
-                }
-
-                // If we got this far, we found a valid candidate
-                return candidate;
-            }
-
-            // Candidate not found, so let's create one
-            final List<AnnotationMetadataBuilder> annotations = new ArrayList<AnnotationMetadataBuilder>();
-            final AnnotationMetadataBuilder annotationBuilder = new AnnotationMetadataBuilder(
-                    PERSISTENCE_CONTEXT);
-            if (StringUtils.isNotBlank(crudAnnotationValues
-                    .getPersistenceUnit())) {
-                annotationBuilder.addStringAttribute("unitName",
-                        crudAnnotationValues.getPersistenceUnit());
-            }
-            annotations.add(annotationBuilder);
-
-            return new FieldMetadataBuilder(getId(), Modifier.TRANSIENT,
-                    annotations, fieldSymbolName, ENTITY_MANAGER).build();
-        }
-    }
-
-    /**
-     * @return the static utility entityManager() method used by other methods
-     *         to obtain entity manager and available as a utility for user code
-     *         (never returns nulls)
-     */
-    public MethodMetadata getEntityManagerMethod() {
-        return entityManagerMethod;
-    }
-
-    /**
-     * Returns the JPA name of this entity.
-     * 
-     * @return a non-<code>null</code> name (might be empty)
-     */
-    public String getEntityName() {
-        return entityName;
-    }
-
     /**
      * @return the find all method (may return null)
      */
@@ -540,13 +574,6 @@
public class JpaActiveRecordMetadata extends
         return methodBuilder.build();
     }
 
-    /**
-     * @return the find (by ID) method (may return null)
-     */
-    public MethodMetadata getFindMethod() {
-        return findMethod;
-    }
-
     /**
      * @return the flush method (never returns null)
      */
@@ -595,13 +622,6 @@
public class JpaActiveRecordMetadata extends
                 "persist");
     }
 
-    /**
-     * @return the pluralised name (never returns null or an empty string)
-     */
-    public String getPlural() {
-        return plural;
-    }
-
     /**
      * @return the remove method (may return null)
      */
@@ -781,17 +801,4 @@
public class JpaActiveRecordMetadata extends
         builder.addMethod(methodBuilder);
         findMethod = methodBuilder.build();
     }
-
-    @Override
-    public String toString() {
-        final ToStringBuilder builder = new ToStringBuilder(this);
-        builder.append("identifier", getId());
-        builder.append("valid", valid);
-        builder.append("aspectName", aspectName);
-        builder.append("destinationType", destination);
-        builder.append("finders", crudAnnotationValues.getFinders());
-        builder.append("governor", governorPhysicalTypeMetadata.getId());
-        builder.append("itdTypeDetails", itdTypeDetails);
-        return builder.toString();
-    }
 }
